﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Sybercare_ProductTool_WriteSn.Msc;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading;
using System.IO.Ports;

namespace Sybercare_ProductTool_WriteSn
{
    public partial class WriteSnForm : Form
    {
        private string configFilePath = Directory.GetCurrentDirectory() + "\\Config\\" + "app.ini";         //配置文件路径

        //校准写号下载功能相关变量
        private int jlinkDevCount = 0;                                                                      //jlink设备连接数
        private bool isJlinkConnect = false;                                                                //是否有jlink接入
        private BackgroundWorker bgw_WriteSnProgProc;

        //校准写号功能相关变量
        const int AllowDeviceIdCharCnt = 8;             //设备ID允许的长度
        const int AllowVendorIdCharCnt = 5;             //厂商ID允许的长度
        const int AllowDeviceIdCharRangeCnt = 13;       //设备ID最大允许范围的长度

        const byte PktHeader = 0x7C;                    //包头
        const byte PktTail = 0x7D;                      //包尾
        const byte PktFieldCmd = 0x01;                  //命令包标示
        const byte PktFieldData = 0x02;                 //数据包标示

        const byte ConfigVendorIdCmdCode = 0x08;         //配置厂商ID命令码
        const byte ConfigDeviceIdCmdCode = 0x07;         //配置设备ID命令码
        const byte CaliLeftAdCmdCode = 0x09;             //校准左边AD命令码
        const byte CaliRightAdCmdCode = 0x0A;            //校准右边AD命令码
        const byte LeaveFactModeCmdCode = 0x06;          //离开工厂模式命令码

        const byte ConfigVendorIdResponse = 0x13;        //配置厂商ID回馈码
        const byte ConfigDeviceIdResponse = 0x12;        //配置设备ID回馈码
        const byte CaliLeftAdResponse = 0x14;            //校准左边AD回馈码
        const byte CaliRightAdResponse = 0x15;           //校准右边AD回馈码
        const byte BtMacResponse = 0x10;                 //BT MAC回馈码

        const byte FactoryInfoVendorIdCmdCode = 0x0B;    //厂商信息区厂商Id设置命令码
        const byte FactoryInfoDeviceIdCmdCode = 0x0D;    //厂商信息区设备Id设置命令码 

        private int TextBoxDeviceIdCharCnt = 0;
        private int TextBoxVendorIdCharCnt = 0;

        private int AdOffsetMax = 100;                   //AD采集固定电阻偏差最大值
        private int AdOffsetMin = -100;                  //AD采集固定电阻偏差最小值

        public string iPort = "com20";                  //默认为串口20
        public int iRate = 38400;
        public byte bSize = 8;                          //8 bits
        public int iTimeout = 1000;                     //延时时长
        public SerialPort sp = new SerialPort();        //定义一个串口类的串口变量
        private BackgroundWorker bgw_WriteSnProc;
        private System.Timers.Timer PcToMcuTimer;       //PC下发数据用的定时器
        private int PcToMcuStage = 0;                   //PC下发数据的状态

        //界面显示方面的变量
        private System.Timers.Timer DelayDispTimer = new System.Timers.Timer(1200);

        /// <summary>
        /// 写号校准主窗口构造函数
        /// </summary>
        public WriteSnForm()
        {
            InitializeComponent();
            CheckDebugTextDisp();
            CheckJlinkIsConnectedPc();
            ProgressBarEventHandlerInit();
            MainFormDefaultDisp();
        }

        /// <summary>
        /// 主窗口默认控件显示状态
        /// </summary>
        private void MainFormDefaultDisp()
        {
            lb_WriteSn_Download_State.Visible = false;
            lb_WriteSn_State.Visible = false;
            OneKey_Button.Focus();
            OneKey_Button.Select();
        }

        /// <summary>
        /// 进度条事件处理初始化
        /// </summary>
        private void ProgressBarEventHandlerInit()
        {
            ///Bgw_WriteSnProgProc 事件处理配置
            Bgw_WriteSnProgProc = new BackgroundWorker();
            Bgw_WriteSnProgProc.WorkerReportsProgress = true;
            Bgw_WriteSnProgProc.WorkerSupportsCancellation = false;

            Bgw_WriteSnProgProc.DoWork += new DoWorkEventHandler(Bgw_WriteSnProgProc_DoWork);
            Bgw_WriteSnProgProc.ProgressChanged += new ProgressChangedEventHandler(Bgw_WriteSnProgProc_ProgressChanged);
            Bgw_WriteSnProgProc.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Bgw_WriteSnProgProc_RunWorkerCompleted);

            ///Bgw_WriteSnProc 事件处理配置
            Bgw_WriteSnProc = new BackgroundWorker();
            Bgw_WriteSnProc.WorkerReportsProgress = true;
            Bgw_WriteSnProc.WorkerSupportsCancellation = false;

            Bgw_WriteSnProc.DoWork += new DoWorkEventHandler(Bgw_WriteSnProc_DoWork);
            Bgw_WriteSnProc.ProgressChanged += new ProgressChangedEventHandler(Bgw_WriteSnProc_ProgressChanged);
            Bgw_WriteSnProc.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Bgw_WriteSnProc_RunWorkerCompleted);

            Bgw_WriteSnProc.RunWorkerAsync(this);

            PcToMcuTimer = new System.Timers.Timer(180); //100ms
            PcToMcuTimer.Elapsed += PcToMcuTimer_Elapsed;
            PcToMcuTimer.AutoReset = true;

            //延时定时器溢出处理回调
            DelayDispTimer.Elapsed += DelayDisp_TimerHandler;           //添加延时显示定时器处理函数
            DelayDispTimer.AutoReset = false;

            //串口操作相关初始化
            sp.DataReceived += dataReciveHander;
        }

        //校准写号下载功能相关方法
        /// <summary>
        /// 检查调试文本是否显示
        /// </summary>
        private void CheckDebugTextDisp()
        {
            if (File.Exists(configFilePath))
            {
                IniFile ini = new IniFile(configFilePath);

                try
                {
                    string iniVal = ini.IniReadValue("DispDebugText", "DispAttr");

                    if (iniVal == "true")
                    {
                        ProgDebug_Text.Visible = true;
                        lb_download_log.Visible = true;
                        WriteSnDebug_Text.Visible = true;
                        lb_writesn_prograss.Visible = true;
                    }
                    else if (iniVal == "false")
                    {
                        ProgDebug_Text.Visible = false;
                        lb_download_log.Visible = false;
                        WriteSnDebug_Text.Visible = false;
                        lb_writesn_prograss.Visible = false;
                    }

                }
                catch
                {
                    MessageBox.Show(this, "配置文件读取失败", "错误", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Exclamation);  //弹框提示       
                }
            }
            else
            {
                MessageBox.Show(this, "配置文件丢失，请联系开发厂家", "错误", MessageBoxButtons.OK, MessageBoxIcon.Stop);  //弹框提示

                System.Environment.Exit(0);                    //退出整个程序
            }
        }

        /// <summary>
        /// 显示jlink设备数
        /// </summary>
        /// <param name="devices"></param>
        private void PopulateJlinkDevComboBox(IEnumerable<string> devices)
        {
            List<string> devs = new List<string>(devices);
            jlinkDevCount = devs.Count;
            jlink_sn_combox.DataSource = devs;
        }

        /// <summary>
        /// 检查jlink是否连接上PC
        /// </summary>
        private void CheckJlinkIsConnectedPc()
        {
            string[] keys = new string[10];
            string[] vals = new string[10];
            Collection<string> jlinkdev = new Collection<string>();
            jlinkdev.Clear();                                           //清空jlinkdev所有元素

            Process pgmProc = new Process();
            pgmProc.StartInfo.FileName = "nrfjprog.exe";
            pgmProc.StartInfo.Arguments = "--ids";
            pgmProc.StartInfo.CreateNoWindow = true;
            pgmProc.StartInfo.RedirectStandardError = true;
            pgmProc.StartInfo.RedirectStandardInput = true;
            pgmProc.StartInfo.RedirectStandardOutput = true;
            pgmProc.StartInfo.UseShellExecute = false;

            try
            {
                pgmProc.Start();                                        //启动nrfjprog.exe进程

                string errstr = pgmProc.StandardError.ReadToEnd();      //读取进程错误的流

                if (errstr != "")
                {//产生错误
                    this.Invoke((MethodInvoker)delegate()
                    {
                        this.ProgDebug_Text.Text += "ErrOut:" + errstr;//异步将错误信息输出到DebugText上    
                    });
                }

                string outstr = pgmProc.StandardOutput.ReadToEnd();    //读取进程标准输出流

                if (outstr != "")
                { //正常接入的jlink串口号
                    char[] splitchar = { '\r', '\n' };
                    string[] ostr = outstr.Split(splitchar, StringSplitOptions.RemoveEmptyEntries);     //得到jlink设备的串号

                    ///获取配置文件中可忽略jlink串号
                    IniFile ini = new IniFile(configFilePath);
                    try
                    {
                        ini.GetAllKeyValues("IgnoreDev", out keys, out vals);

                        bool isIngore = false;
                        foreach (string jlinksn in ostr)
                        {
                            foreach (string DevSn in vals)
                            {
                                if (jlinksn == DevSn)
                                {
                                    isIngore = true;
                                }
                                else
                                {

                                }
                            }
                            if (!isIngore)
                            {
                                jlinkdev.Add(jlinksn);                //将搜索到的jlink设备号加入复选框
                            }
                            else
                            {
                                isIngore = false;
                            }
                        }
                    }
                    catch
                    {

                    }
                }

                //获得jlink串号
                if (jlinkdev.Count != 0)
                {
                    PopulateJlinkDevComboBox(jlinkdev);
                    isJlinkConnect = true;
                }
                else
                {//没有jlink设备则弹框提示 
                    isJlinkConnect = false;
                    DialogResult rslt = MessageBox.Show(this, "没有下载器设备接入，请接入下载器设备到电脑后点击确定键", "错误", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);  //弹框提示没有jlink设备接入       
                    if (rslt == DialogResult.OK)
                    {
                        CheckJlinkIsConnectedPc();                   //检查jlink的连接性   
                    }
                    else if (rslt == DialogResult.Cancel)
                    {
                        Environment.Exit(0);  
                    }
                }
            }
            catch 
            {
                DialogResult rslt = MessageBox.Show(this, "nrfstudio程序没有安装，请获取开发厂家支持", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                if (rslt == DialogResult.OK)
                {
                    Environment.Exit(0);
                }
            }
        }

        /// <summary>
        /// 下载固件程序
        /// </summary>
        private void DownloadFirmware(string selectDevSn, string hexpath)
        {
            Process nrfjprogProcess = new Process();
            ProcessStartInfo nrfjprogStartInfo = new ProcessStartInfo();

            ///////////////////////////////////////////////////////stage1

            bgw_WriteSnProgProc.ReportProgress(0, 1);                                                               //开始擦除

            nrfjprogStartInfo.FileName = "nrfjprog.exe";
            nrfjprogStartInfo.Arguments = " --snr " + selectDevSn + " --eraseall ";                     //擦除整个芯片的内容
            nrfjprogStartInfo.UseShellExecute = false;
            nrfjprogStartInfo.RedirectStandardError = true;
            nrfjprogStartInfo.RedirectStandardInput = true;
            nrfjprogStartInfo.RedirectStandardOutput = true;
            nrfjprogStartInfo.CreateNoWindow = true;

            nrfjprogProcess.StartInfo = nrfjprogStartInfo;

            string errstr = "";
            string outstr = "";

            try
            {
                nrfjprogProcess.Start();

                errstr = nrfjprogProcess.StandardError.ReadToEnd();
                if (errstr != "")
                {
                    ProgDebug_TextBox_AppendText("错误记录:\r\n" + errstr);

                    bgw_WriteSnProgProc.ReportProgress(50, 1);
                    MessageBox.Show(this, "请保证固件下载过程中下载设备与夹具间的稳定连接,擦除阶段", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }

                outstr = nrfjprogProcess.StandardOutput.ReadToEnd();
                if (outstr != "")
                {
                    ProgDebug_TextBox_AppendText("正常输出:\r\n" + outstr);
                    if (outstr.IndexOf("ERROR:") > -1)
                    {
                        bgw_WriteSnProgProc.ReportProgress(50, 1);
                        MessageBox.Show(this, "请保证固件下载过程中下载设备与夹具间的稳定连接,擦除阶段", "告警", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        return;
                    }
                }
            }
            catch
            {

            }
            bgw_WriteSnProgProc.ReportProgress(30, 2);                                                                          //汇报program进度
            nrfjprogProcess.WaitForExit();

            ////////////////////////////////////////////////////stage2
            nrfjprogStartInfo.Arguments = " --snr " + selectDevSn + " --program " + "\"" + hexpath + "\""+ " --verify";          //下载合并的hex文件
            nrfjprogProcess.StartInfo = nrfjprogStartInfo;

            bgw_WriteSnProgProc.ReportProgress(10, 1);                                                                          //开始编程

            nrfjprogProcess.Start();

            errstr = "";
            outstr = "";
            errstr = nrfjprogProcess.StandardError.ReadToEnd();
            if (errstr != "")
            {
                ProgDebug_TextBox_AppendText("错误记录:\r\n" + errstr);
                bgw_WriteSnProgProc.ReportProgress(50, 1);
                MessageBox.Show(this, "请保证固件下载过程中下载设备与夹具间的稳定连接,下载固件阶段", "告警", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }
            outstr = nrfjprogProcess.StandardOutput.ReadToEnd();
            if (outstr != "")
            {
                ProgDebug_TextBox_AppendText(hexpath + "\r\n" + "正常输出：\r\n" + outstr);
                if (outstr.IndexOf("ERROR") > -1)
                {
                    bgw_WriteSnProgProc.ReportProgress(50, 1);
                    MessageBox.Show(this, "请保证固件下载过程中下载设备与夹具间的稳定连接,下载固件阶段", "告警", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }
                if (outstr.IndexOf("Verify OK.") > -1)
                {
                    bgw_WriteSnProgProc.ReportProgress(20, 1);                                                      //验证成功   
                }
            }
            bgw_WriteSnProgProc.ReportProgress(60, 2);
            nrfjprogProcess.WaitForExit();

            ///////////////////////////////////////////////////stage3
            bgw_WriteSnProgProc.ReportProgress(30, 1);                                                              //开始复位
            nrfjprogStartInfo.Arguments = " --snr " + selectDevSn + " --reset ";                        //复位
            nrfjprogProcess.StartInfo = nrfjprogStartInfo;

            nrfjprogProcess.Start();

            errstr = "";
            outstr = "";
            errstr = nrfjprogProcess.StandardError.ReadToEnd();
            if (errstr != "")
            {
                ProgDebug_TextBox_AppendText("错误输出:\r\n" + errstr);
                bgw_WriteSnProgProc.ReportProgress(50, 1);
                MessageBox.Show(this, "请保证固件下载过程中下载设备与夹具间的稳定连接,复位阶段", "告警", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }
            outstr = nrfjprogProcess.StandardOutput.ReadToEnd();
            if (outstr != "")
            {
                ProgDebug_TextBox_AppendText("正常输出:\r\n" + outstr);
                if (outstr.IndexOf("ERROR") > -1)
                {
                    bgw_WriteSnProgProc.ReportProgress(50, 1);
                    MessageBox.Show(this, "请保证固件下载过程中下载设备与夹具间的稳定连接,下载固件阶段", "告警", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }
            }

            bgw_WriteSnProgProc.ReportProgress(100, 2);
            bgw_WriteSnProgProc.ReportProgress(40, 1);
            nrfjprogProcess.WaitForExit();

            DelayDispTimer.Start();                                 //启动延时定时器

            WriteSnProg_SuccAction();                               //写号下载成功后动作
        }

        /// <summary>
        /// 检查jlink上连接的设备的连接性
        /// </summary>
        private bool CheckJlinkConnectedDev()
        {
            Process nrfjprogProc = new Process();
            ProcessStartInfo nrfjprogStartInfo = new ProcessStartInfo();

            nrfjprogStartInfo.FileName = "nrfjprog.exe";
            nrfjprogStartInfo.CreateNoWindow = true;
            nrfjprogStartInfo.Arguments = " --snr " + jlink_sn_combox.Items[0] + " --readregs";         //选择复选框置顶的序列号设备
            nrfjprogStartInfo.RedirectStandardError = true;
            nrfjprogStartInfo.RedirectStandardInput = true;
            nrfjprogStartInfo.RedirectStandardOutput = true;
            nrfjprogStartInfo.UseShellExecute = false;

            nrfjprogProc.StartInfo = nrfjprogStartInfo;
            nrfjprogProc.Start();

            //标准错误输出字符串
            string errstr;
            errstr = nrfjprogProc.StandardError.ReadToEnd();
            if (errstr != "")
            {
                this.Invoke((MethodInvoker)delegate()
                {
                    ProgDebug_TextBox_AppendText("错误记录:\r\n" + errstr);
                });
            }

            //标准输出字符串
            string outstr;
            outstr = nrfjprogProc.StandardOutput.ReadToEnd();
            if (outstr != "")
            {
                this.Invoke((MethodInvoker)delegate()
                {
                    ProgDebug_TextBox_AppendText("输出记录:\r\n" + outstr);
                });
            }

            nrfjprogProc.WaitForExit();                                 //等待nrfjprog.exe进程退出

            if (errstr != "" || outstr.TrimEnd('\n').TrimEnd('\r') == "ERROR: Cannot connect to the nRF51 device.")
            {
                MessageBox.Show(this, "请确保下载器的接线与夹具的接线稳定连接，如果依然有问题请联系生产厂商", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);  //弹框提示没有jlink设备接入              

                return false;
            }
            else if (outstr != "")
            {
                return true;
            }

            return true;
        }

        /// <summary>
        /// 写号下载动作完成后   
        /// </summary>
        private void WriteSnProg_SuccAction()
        {
            TextBox_DeviceId_Select();                              //选中DeviceId文本框
            Serial_Open();                                          //串口打开
        }

        //校准写号功能相关方法

        /// <summary>
        /// 串口打开
        /// </summary>
        private void Serial_Open()
        {
            Parity serParity = Parity.None;
            StopBits serSB = StopBits.One;

            if (!sp.IsOpen)
            {
                sp.PortName = iPort;
                sp.BaudRate = iRate;
                sp.DataBits = bSize;
                sp.Parity = serParity;
                sp.StopBits = serSB;
                sp.ReadTimeout = iTimeout;

                try
                {
                    sp.Open();
                    Trace.WriteLine("\n\n\n串口被打开\n\n");
                }
                catch
                {
                    MessageBox.Show(this, "串口打开失败,请将校准写号的串口连接器接入，并确保串口号指定为COM20", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    
                    OneKey_Button_Select();
                }   
            }
        }

        /// <summary>
        /// 串口关闭
        /// </summary>
        private void Serial_Close()
        {
            try
            {
                if (sp.IsOpen)
                {
                    sp.Close();                                 //关闭串口
                }
            }
            catch 
            {
            
            }
        }

        /// <summary>
        /// 串口写入配置方法
        /// </summary>
        /// <param name="pktid">包标示</param>
        /// <param name="opcode">操作码</param>
        /// <param name="ficode">厂商操作码</param>
        /// <param name="content">包有效内容</param>
        /// <param name="count">包有效内容字节数</param>
        private void Serial_Write_Config(byte pktid, byte opcode, byte ficode, byte[] content, byte count)
        {//串口写入配置
            byte[] DownToMcuBuffer = new byte[16];

            DownToMcuBuffer[0] = PktHeader;
            DownToMcuBuffer[15] = PktTail;
            DownToMcuBuffer[1] = (byte)((opcode << 2) | pktid);
            DownToMcuBuffer[2] = (byte)(count + 1);
            Array.Copy(content, 0, DownToMcuBuffer, 3, count);
            DownToMcuBuffer[count + 3] = ficode;
            try
            {
                sp.Write(DownToMcuBuffer, 0, 16);
            }
            catch (System.InvalidOperationException e)
            {
                MessageBox.Show(this, "请将校准写号的串口线接入，并确保串口号指定为COM20", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            catch
            {
                Trace.WriteLine("串口写入的其他错误，请检查...");
            }
        }

        private string adleft_offset = "0";
        private string adright_offset = "0";
        /// <summary>
        /// 串口读取数据解析
        /// </summary>
        /// <param name="decode_buf">解析缓冲区</param>
        /// <param name="count">个数</param>
        private void Serial_Read_Decode(byte[] decode_buf, int count)
        {//串口读取配置解码
            if ((decode_buf[0] == PktHeader) && ((decode_buf[count - 3] == PktTail) || (decode_buf[count - 4] == PktTail)))
            { //为有效的配置回馈包
                byte pktfield = 0;
                byte pktavasize = 0;
                byte pktid = 0;
                byte cmdcode = 0;

                pktavasize = decode_buf[2];
                pktfield = decode_buf[1];
                pktid = (byte)(pktfield & 0x03);
                cmdcode = (byte)(pktfield >> 2);

                if (pktid == PktFieldCmd)
                {//命令
                    switch (cmdcode)
                    {
                        case ConfigVendorIdResponse:
                            {//配置厂商ID
                                byte status = 0x00;
                                status = decode_buf[3];
                                if (status == 0x01)
                                {
                                    PcToMcuTimer.Start();
                                    PcToMcuStage = 1;               //下发设备id配置
                                }
                                else
                                {

                                }
                            }
                            break;
                        case ConfigDeviceIdResponse:
                            {//配置设备ID
                                byte status = 0x00;
                                status = decode_buf[3];
                                if (status == 0x01)
                                {
                                    PcToMcuTimer.Start();
                                    PcToMcuStage = 2;               //下发校准左边AD
                                }
                                else
                                {

                                }
                            }
                            break;
                        case CaliLeftAdResponse:
                            {
                                adleft_offset = Encoding.Default.GetString(decode_buf, 3, pktavasize);
                                this.Invoke((MethodInvoker)delegate
                                {
                                    TextBox_LeftAdCali.Text = adleft_offset;
                                });

                                PcToMcuTimer.Start();
                                PcToMcuStage = 3;

                            }
                            break;
                        case CaliRightAdResponse:
                            {
                                adright_offset = Encoding.Default.GetString(decode_buf, 3, pktavasize);
                                this.Invoke((MethodInvoker)delegate
                                {
                                    TextBox_RightAdCali.Text = adright_offset;   
                                });

                                if ((Convert.ToInt32(adleft_offset) < AdOffsetMax && Convert.ToInt32(adleft_offset) > AdOffsetMin) && (Convert.ToInt32(adright_offset) < AdOffsetMax && Convert.ToInt32(adright_offset) > AdOffsetMin))
                                {
                                    PcToMcuTimer.Start();
                                    PcToMcuStage = 4;
                                }
                                else
                                {
                                    bgw_WriteSnProc.ReportProgress(30, 1);
                                    bgw_WriteSnProc.ReportProgress(0, 2);

                                    OneKey_Button_Select();             //选中OneKey_Button

                                    //MessageBox.Show(this, "测温AD校准值误差过大，测温AD测量部分有问题", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                                }
                            }
                            break;
                        case BtMacResponse:
                            {
                                string BtMac;
                                BtMac = Encoding.Default.GetString(decode_buf, 3, pktavasize);

                                PcToMcuTimer.Start();
                                PcToMcuStage = 5;
                            }
                            break;
                        default:
                            break;
                    }
                }
                else if (pktid == PktFieldData)
                {//数据

                }
                else
                {

                }
            }
        }

        private string readStr = "";
        private void dataReciveHander(object sender, EventArgs e)
        {
            readStr += sp.ReadExisting();        //一直读取串口流中的数据,直到读空
            //readStr = sp.ReadLine();

            if (readStr.Length > 4)
            {
                byte[] McuToPcBuffer;
                McuToPcBuffer = new UTF8Encoding(true).GetBytes(readStr);

                Serial_Read_Decode(McuToPcBuffer, McuToPcBuffer.Length);

                WriteSnDebug_TextBox_AppendText(readStr);

                readStr = "";
            }
            else
            {

            }
        }

        /// <summary>
        /// 写号成功后动作
        /// </summary>
        private void WriteSn_SuccAction()
        {
            OneKey_Button_Select();                             //选中OneKey_Button  
            CheckJlinkIsConnectedPc();                          //检测连接到PC上的jlink设备
        }

        #region 窗体UI界面事件响应

        /// <summary>
        /// 选中TextBox_DeviceId文本框
        /// </summary>
        private void TextBox_DeviceId_Select()
        {
            this.Invoke((MethodInvoker)delegate
            {
                TextBox_DeviceId.Text = "";
                TextBox_DeviceId.Focus();
                TextBox_DeviceId.Select();
                OneKey_Button.Enabled = false;

                lb_WriteSn_State.Text = "";
                lb_WriteSn_State.Visible = true;

            });
        }

        /// <summary>
        /// OneKey按钮选中
        /// </summary>
        private void OneKey_Button_Select()
        {
            this.Invoke((MethodInvoker)delegate
            {
                OneKey_Button.Focus();
                OneKey_Button.Select();
                OneKey_Button.Enabled = true;
            });   
        }

        /// <summary>
        /// 下载按键点击事件处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OneKey_Button_Click(object sender, EventArgs e)
        {
            if (!Bgw_WriteSnProgProc.IsBusy)
            {
                bool isDevConnected = false;

                WriteSnCali_ProcessBar.Value = 0;
                lb_WriteSn_State.Text = "";
                lb_WriteSn_State.Visible = false;

                isDevConnected = CheckJlinkConnectedDev();                       //检查设备连接性

                if (isDevConnected)
                {
                    try
                    {
                        Bgw_WriteSnProgProc.RunWorkerAsync(this);                //启动后台下载进程      
                    }
                    catch
                    {

                    }
                }  
            }
        }

        /// <summary>
        /// 控件ProgDebug_TextBox追加文本
        /// </summary>
        /// <param name="appendText"></param>
        private void ProgDebug_TextBox_AppendText(string appendText)
        {
            this.Invoke((MethodInvoker)delegate
            {
                ProgDebug_Text.Text += appendText;
                ProgDebug_Text.Focus();
                ProgDebug_Text.Select(ProgDebug_Text.TextLength, 0);
                ProgDebug_Text.ScrollToCaret();
            });
        }

        /// <summary>
        /// 向WriteSnDebug_TextBox追加数据
        /// </summary>
        /// <param name="appendText"></param>
        private void WriteSnDebug_TextBox_AppendText(string appendText)
        {
            this.Invoke((MethodInvoker)delegate
            {
                WriteSnDebug_Text.Text += appendText;
                WriteSnDebug_Text.Focus();
                WriteSnDebug_Text.Select(WriteSnDebug_Text.TextLength, 0);
                WriteSnDebug_Text.ScrollToCaret();
            });
        }
        
        /// <summary>
        /// 厂商ID文本框键按下事件处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TextBox_VendorID_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar != '\b')
            {
                if (TextBoxVendorIdCharCnt == 0)
                {
                    TextBox_VendorID.Text = "";
                }

                if (!char.IsLetterOrDigit(e.KeyChar))//只允许输入数字或字母  
                {
                    if (e.KeyChar == '\r')
                    {
                        if (TextBoxVendorIdCharCnt == AllowVendorIdCharCnt)
                        {//符合规定长度的设备ID
                            TextBoxVendorIdCharCnt = 0;
                        }
                        else
                        {
                            TextBoxVendorIdCharCnt = 0;
                            TextBox_DeviceId.Text = "";
                            MessageBox.Show(this, "请输入" + AllowVendorIdCharCnt.ToString() + "个字母或数字的厂商ID", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        }
                    }
                    else
                    {
                        e.Handled = true;
                    }
                }
                else
                {
                    TextBoxVendorIdCharCnt++;
                }
            }
            else
            {
                if (TextBoxVendorIdCharCnt != 0)
                {
                    TextBoxVendorIdCharCnt--;
                }
            }    
        }

        /// <summary>
        /// 设备ID文本框键按下事件处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TextBox_DeviceId_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar != '\b')
            {
                if (TextBoxDeviceIdCharCnt == 0)
                {
                    TextBox_DeviceId.Text = "";
                }
                if ((e.KeyChar < '0') || (e.KeyChar > '9'))//这是允许输入0-9数字  
                {
                    if (e.KeyChar == '\r')
                    {
                        if (TextBoxDeviceIdCharCnt <= AllowDeviceIdCharRangeCnt && TextBoxDeviceIdCharCnt > 7)
                        {//现手头上的条码没有8个数字
                            TextBoxDeviceIdCharCnt = 0;

                            lb_WriteSn_Download_State.Text = "";
                            lb_WriteSn_Download_State.Visible = false;

                            //向串口写入序列号
                            if (TextBox_VendorID.Text != "" && TextBox_VendorID.Text.Length == AllowVendorIdCharCnt)
                            {
                                byte[] VendorIdBuf = new byte[8];
                                string VendorIdStr = TextBox_VendorID.Text.Substring(TextBox_VendorID.Text.Length - AllowVendorIdCharCnt);
                                VendorIdStr = VendorIdStr + "000";
                                VendorIdBuf = Encoding.ASCII.GetBytes(VendorIdStr);
                                bgw_WriteSnProc.ReportProgress(10, 1);            //写号中
                                Serial_Write_Config(PktFieldCmd, ConfigVendorIdCmdCode, FactoryInfoVendorIdCmdCode, VendorIdBuf, 8);
                            }
                            else
                            {
                                byte[] DeviceIdBuf = new byte[8];
                                string DeviceIdStr = TextBox_DeviceId.Text.Substring(TextBox_DeviceId.Text.Length - 8);
                                DeviceIdBuf = Encoding.ASCII.GetBytes(DeviceIdStr);
                                Serial_Write_Config(PktFieldCmd, ConfigDeviceIdCmdCode, FactoryInfoDeviceIdCmdCode, DeviceIdBuf, 8);
                            }
                        }
                        //if (TextBoxDeviceIdCharCnt == AllowDeviceIdCharCnt)
                        //{//符合规定长度的设备ID
                        //    TextBoxDeviceIdCharCnt = 0;
                        //}
                        else
                        {
                            TextBoxDeviceIdCharCnt = 0;
                            TextBox_DeviceId.Text = "";
                            MessageBox.Show(this, "请输入至少小于" + AllowDeviceIdCharRangeCnt.ToString() + "个数字的串号" + "或大于7个数字的串号", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        }
                    }
                    else
                    {
                        e.Handled = true;
                    }
                }
                else
                {
                    TextBoxDeviceIdCharCnt++;
                }
            }
            else
            {
                if (TextBoxDeviceIdCharCnt != 0)
                {
                    TextBoxDeviceIdCharCnt--;
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TextBox_LeftAdCali_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TextBox_RightAdCali_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WriteSnForm_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == '\r' && OneKey_Button.Enabled == true)
            {
                e.Handled = true;
                OneKey_Button.PerformClick();                               //完成按键点击动作
            }
        }

        /// <summary>
        /// 窗体关闭
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WriteSnForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            Serial_Close();
        }

        #endregion

        #region 后台进程事件响应
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Bgw_WriteSnProgProc_DoWork(object sender, DoWorkEventArgs e)
        {
            bgw_WriteSnProgProc = sender as BackgroundWorker;

            this.Invoke((MethodInvoker)delegate
            {
                lb_WriteSn_Download_State.Visible = true;
            });

            IniFile ini = new IniFile(configFilePath);                                  //获取配置文件中相应键的值
            string hexpath = Directory.GetCurrentDirectory() + "\\DownloadFilePath\\" + ini.IniReadValue("DownloadHexPath", "DlHexPath");

            if (File.Exists(hexpath))
            {
                DownloadFirmware(jlink_sn_combox.Items[0].ToString(), hexpath);         //下载单个下载器的固件  
            }
            else
            {
                MessageBox.Show(this, "下载固件文件丢失，请联系开发厂商", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Bgw_WriteSnProgProc_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            int user_state = (int)e.UserState;                      //用户状态
            int percnt = e.ProgressPercentage;                      //进度

            if (user_state == 1)
            {
                if (percnt == 0)
                {
                    lb_WriteSn_Download_State.Text = "开始擦除...";
                    lb_WriteSn_Download_State.ForeColor = Color.Blue;
                }
                else if (percnt == 10)
                {
                    lb_WriteSn_Download_State.Text = "开始编程...";
                    lb_WriteSn_Download_State.ForeColor = Color.Blue;
                }
                else if (percnt == 20)
                {
                    lb_WriteSn_Download_State.Text = "编程验证成功.";
                    lb_WriteSn_Download_State.ForeColor = Color.Blue;
                }
                else if (percnt == 30)
                {
                    lb_WriteSn_Download_State.Text = "设备复位";
                    lb_WriteSn_Download_State.ForeColor = Color.Blue;
                }
                else if (percnt == 40)
                {
                    lb_WriteSn_Download_State.Text = "程序运行，请扫码！";
                    lb_WriteSn_Download_State.ForeColor = Color.Blue;
                }
                else if (percnt == 50)
                {
                    lb_WriteSn_Download_State.Text = "未知错误！";
                    lb_WriteSn_Download_State.ForeColor = Color.Red;
                }
            }
            else if (user_state == 2)
            {
                ProgramProcessBar.Value = percnt;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Bgw_WriteSnProgProc_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //this.Invoke((MethodInvoker)delegate
            //{
            //    ProgramProcessBar.Value = 0;
            //    lb_AntenaTest_Download_State.Text = "";
            //    lb_AntenaTest_Download_State.Visible = false;
            //});   
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Bgw_WriteSnProc_DoWork(object sender, DoWorkEventArgs e)
        {
            bgw_WriteSnProc = sender as BackgroundWorker;

            while (true)
            {
                Thread.Sleep(10000);                  //后台线程10000ms执行一次
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Bgw_WriteSnProc_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            int userstate = (int)e.UserState;
            int percnt = e.ProgressPercentage;

            if (userstate == 1)
            {
                if (percnt == 0)
                {
                    lb_WriteSn_State.Text = "";
                    lb_WriteSn_State.ForeColor = Color.Blue;
                }
                else if (percnt == 10)
                {
                    lb_WriteSn_State.Text = "写号中...";
                    lb_WriteSn_State.ForeColor = Color.Blue;
                }
                else if (percnt == 20)
                {
                    lb_WriteSn_State.Text = "校准中...";
                    lb_WriteSn_State.ForeColor = Color.Blue;
                }
                else if (percnt == 30)
                {
                    lb_WriteSn_State.Text = "校准失败,固定电阻采集偏差值过大！";
                    lb_WriteSn_State.ForeColor = Color.Red;
                }
                else if (percnt == 40)
                {
                    lb_WriteSn_State.Text = "校准写号成功";
                    lb_WriteSn_State.ForeColor = Color.Blue;
                }
            }
            else if (userstate == 2)
            {
                WriteSnCali_ProcessBar.Value = percnt;      //显示进度   
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Bgw_WriteSnProc_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

        }

        /// <summary>
        /// PC下发数据到MCU定时器溢出处理函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PcToMcuTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {//定时器超时回调
            byte[] DownloadBuf = new byte[8];
            string DownloadStr;

            if (PcToMcuStage == 1)
            {
                DownloadStr = TextBox_DeviceId.Text.Substring(TextBox_DeviceId.Text.Length - 8);
                DownloadBuf = Encoding.ASCII.GetBytes(DownloadStr);
                Serial_Write_Config(PktFieldCmd, ConfigDeviceIdCmdCode, FactoryInfoDeviceIdCmdCode, DownloadBuf, (byte)DownloadBuf.Length);
            }
            else if (PcToMcuStage == 2)
            {
                DownloadStr = "LftAdOst";
                DownloadBuf = Encoding.ASCII.GetBytes(DownloadStr);
                bgw_WriteSnProc.ReportProgress(20, 1);           //校准中
                bgw_WriteSnProc.ReportProgress(30, 2);           //显示进度30%
                Serial_Write_Config(PktFieldCmd, CaliLeftAdCmdCode, 0x00, DownloadBuf, (byte)DownloadBuf.Length);
            }
            else if (PcToMcuStage == 3)
            {
                DownloadStr = "RhtAdOst";
                DownloadBuf = Encoding.ASCII.GetBytes(DownloadStr);
                bgw_WriteSnProc.ReportProgress(60, 2);           //显示进度60%
                Serial_Write_Config(PktFieldCmd, CaliRightAdCmdCode, 0x00, DownloadBuf, (byte)DownloadBuf.Length);
            }
            else if (PcToMcuStage == 4)
            {
                DownloadStr = "LeaveMode";
                DownloadBuf = Encoding.ASCII.GetBytes(DownloadStr);
                bgw_WriteSnProc.ReportProgress(100, 2);
                Serial_Write_Config(PktFieldCmd, LeaveFactModeCmdCode, 0x00, DownloadBuf, (byte)DownloadBuf.Length);
            }

            PcToMcuTimer.Stop();                                 //关掉定时器

            if (PcToMcuStage == 5)
            {
                bgw_WriteSnProc.ReportProgress(40, 1);

                WriteSn_SuccAction();                           //写号成功后动作

                //MessageBox.Show(this, "校准写号成功!请继续接入下一个设备...");
            }
        }

        /// <summary>
        /// 延时显示定时器处理函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DelayDisp_TimerHandler(object sender, System.Timers.ElapsedEventArgs e)
        {
            this.Invoke((MethodInvoker)delegate
            {
                ProgramProcessBar.Value = 0;
                //lb_WriteSn_Download_State.Text = "";
                //lb_WriteSn_Download_State.Visible = false;
            });

            DelayDispTimer.Stop();
        }

        #endregion

    }
}
